package com.strawcom.charmring.bean;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;

import org.litepal.crud.DataSupport;

import android.annotation.SuppressLint;

import com.strawcom.charmring.App;
import com.strawcom.charmring.C;
import com.strawcom.charmring.bluetooth.RingBleController;
import com.strawcom.charmring.util.FormatUtil;
import com.strawcom.charmring.util.LogUtil;
import com.strawcom.charmring.util.PreferenceUtil;

/**
 * @author WangPeng
 * 
 */
@SuppressLint("SimpleDateFormat")
public class Calories extends DataSupport {
	/** 默认体重 */
	public static final float DEFAULT_WEIGHT = 60f;
	/** 默认年龄 */
	public static final int DEFAULT_AGE = 20;
	/** 默认性别：女 */
	public static final boolean DEFAULT_MALE = false;
	/** 默认升高 */
	public static final int DEFAULT_HEIGHT = 165;

	private int id;
	/** 运动类型 */
	private int type;
	/** 累计距离 m */
	private float distance;
	/** 累计持续时间 分钟 */
	private int duration;
	/** 消耗能量 卡路里 */
	private float calorie;
	/** 步 */
	private int step;

	private DailySummary dailySummary;
	/** 记录时间 [hh:mm] */
	private String recordTimeInfo;
	/** 距离2000年1月1号的秒数 */
	private long recordTime;

	/** 运动类型 安静 */
	public static final int TYPE_QUIET = 0;
	/** 运动类型 运动(健美操) */
	public static final int TYPE_SPORT = 1;
	/** 运动类型 步行 */
	public static final int TYPE_WALK = 2;
	/** 运动类型 奔跑 */
	public static final int TYPE_RUN = 3;
	/** 运动类型 自行车 */
	public static final int TYPE_BICYCLE = 4;

	/* 运动量对应于基础代谢率的比率 */
	/** 睡觉 */
	private static final float INDEX_REST = 0.2f;
	/** 静坐，办公室办公，开车，读书，绘画 */
	private static final float INDEX_VERYLIGHT_SPORTS = 0.5f;
	/** 步行 */
	private static final float INDEX_LIGHT_SPORTS = 1.0f;
	/** 快速步行，有氧健身操 */
	private static final float INDEX_MODERATE_SPORTS = 2.5f;
	/** 跑步，激烈的球类运动 */
	private static final float INDEX_HEAVY_SPORTS = 6.0f;

	private static final SimpleDateFormat sdfRecordTime = new SimpleDateFormat(C.exercise.record_time_pattern);
	static{
		// 由于t2000ToCurrent返回的时间并不是东八区的
		sdfRecordTime.setTimeZone(TimeZone.getTimeZone("GMT+8"));
	}
	
	public Calories() {
		// LitePal need public
	}

	private static float calcExerciseDistance(int exerciseMode, int duration, int step, float userHeight) {
		if (exerciseMode == TYPE_WALK || exerciseMode == TYPE_RUN) {
			if (duration == 0) {
				return 0;
			}

			/* 计算2秒内的平均步数，可以得出步幅 */
			float stepAvg = step / (duration * 30);
			float stride = 0;
			if (stepAvg >= 0 && stepAvg < 2) {
				stride = userHeight / 5;
			}
			else if (stepAvg >= 2 && stepAvg < 3) {
				stride = userHeight / 4;
			}
			else if (stepAvg >= 3 && stepAvg < 4) {
				stride = userHeight / 3;
			}
			else if (stepAvg >= 4 && stepAvg < 5) {
				stride = userHeight / 2;
			}
			else if (stepAvg >= 5 && stepAvg < 6) {
				stride = userHeight / 1.2f;
			}
			else if (stepAvg >= 6 && stepAvg < 8) {
				stride = userHeight;
			}
			else if (stepAvg >= 8) {
				stride = userHeight * 1.2f;
			}
			float result = stride * step / 100;
			return result;
		}
		else {
			return 0;
		}
	}

	static float calcExerciseCalories(float spKh, float mUserWeight, float duration, int mUserAge, boolean mUserMale,
			int reportType, int stepNumber) {
		float reportCalorie = 0;
		if (spKh != 0 && duration != 0) {
			float hour = duration / 60;

			float sp3Min400M = 24.0f / spKh;
			float K = 30 / sp3Min400M;
			reportCalorie = mUserWeight * hour * K;

//			LogUtil.e("能量统计【运动类型】：" + reportCalorie + "(weight:"+mUserWeight+",hour:"+hour+",K:"+K+")");
		}
		else {
			float BMR; // 基础代谢率

			if (mUserAge < 9) {
				BMR = mUserMale ? 0.0295f : 0.0279f;
			}
			else if (10 <= mUserAge && mUserAge <= 12) {
				BMR = mUserMale ? 0.0244f : 0.0231f;
			}
			else if (13 <= mUserAge && mUserAge <= 15) {
				BMR = mUserMale ? 0.0205f : 0.0194f;
			}
			else if (16 <= mUserAge && mUserAge <= 19) {
				BMR = mUserMale ? 0.0183f : 0.0168f;
			}
			else if (20 <= mUserAge && mUserAge <= 24) {
				BMR = mUserMale ? 0.0167f : 0.0162f;
			}
			else if (25 <= mUserAge && mUserAge <= 34) {
				BMR = mUserMale ? 0.0159f : 0.0153f;
			}
			else if (35 <= mUserAge && mUserAge <= 54) {
				BMR = mUserMale ? 0.0154f : 0.0147f;
			}
			else if (55 <= mUserAge && mUserAge <= 69) {
				BMR = mUserMale ? 0.0151f : 0.0144f;
			}
			else {
				BMR = mUserMale ? 0.0145f : 0.0144f;
			}

			switch (reportType) {
			case TYPE_QUIET:
				if (stepNumber > 0) {
					reportCalorie = INDEX_VERYLIGHT_SPORTS * BMR * mUserWeight * (duration / 60);
				}
				else {
					reportCalorie = INDEX_REST * BMR * mUserWeight * (duration / 60);
				}
				break;
			case TYPE_SPORT:
				reportCalorie = INDEX_MODERATE_SPORTS * BMR * mUserWeight * (duration / 60);
				break;
			case TYPE_WALK:
				reportCalorie = INDEX_LIGHT_SPORTS * BMR * mUserWeight * (duration / 60);
				break;
			case TYPE_RUN:
				reportCalorie = INDEX_HEAVY_SPORTS * BMR * mUserWeight * (duration / 60);
				break;
			}
//			LogUtil.e("能量统计【安静类型】：" + reportCalorie);
		}

		return reportCalorie;
	}

	public static Calories handleIntance(int t2000ToCurrent, int exerciseMode, int duration, int step,
			DailySummary dailySummary) {
		final float userWeight = PreferenceUtil.readFloat(App.i(), C.sp.weight, DEFAULT_WEIGHT);
		final int userAge = PreferenceUtil.readInt(App.i(), C.sp.user_age, DEFAULT_AGE);
		final boolean userMale = PreferenceUtil.readBoolean(App.i(), C.sp.sex, DEFAULT_MALE);
		final float userHeight = PreferenceUtil.readInt(App.i(), C.sp.height, DEFAULT_HEIGHT);
		
		float distance = calcExerciseDistance(exerciseMode, duration, step, userHeight);
		LogUtil.e("handlerInstance距离:" +distance+"米");
		// 运动速度 km/h
		float speed = distance != 0 ? (float) (distance * 0.06 / duration) : 0;
		LogUtil.e("handlerInstance速度:" +speed+"千米/时");
		float calorie = calcExerciseCalories(speed, userWeight, duration, userAge, userMale, exerciseMode, step);

		// 替换旧数据
		List<Calories> cList =DataSupport.where("dailySummary_id = ? and recordtime = ?",String.valueOf(dailySummary.getId()), String.valueOf(t2000ToCurrent)).find(Calories.class);
		if(cList != null && cList.size() >0) {
			Calories lastCalories = cList.get(0);	
			return replaceInstance(exerciseMode, distance, duration, calorie, step, t2000ToCurrent, dailySummary, lastCalories);
		}
		// or 向数据库插入原始数据
		return newInstance(exerciseMode, distance, duration, calorie, step, t2000ToCurrent, dailySummary);
	}

	private static Calories newInstance(int type, float distance, int duration, float calorie, int stepNumber, int t2000ToCurr,
			DailySummary dailySummary) {
		LogUtil.e("Calories newInstance");
		Calories calories = new Calories();
		calories.type = type;
		calories.distance = distance;
		calories.duration = duration;
		calories.calorie = calorie;
		calories.recordTime = t2000ToCurr;
		calories.recordTimeInfo = sdfRecordTime.format(new Date((t2000ToCurr + RingBleController.offsetTime) * 1000));
		calories.step = stepNumber;
		calories.dailySummary = dailySummary;
		calories.save();
		return calories;
	}

	/**
	 * 根据时间段插入生成一条安静的数据
	 * 
	 * @param startTimestamp
	 *            起始时间戳 ，秒
	 * @param endTimestamp
	 *            结束时间戳，秒
	 * @param isBeginFrom2000
	 *            是否从2000年1月1号开始
	 * 
	 * @return
	 */
	public static Calories newQuietInstance(long startTimestamp, long endTimestamp, DailySummary dailySummary, boolean isBeginFrom2000) {
		Calories cQuiet = new Calories();
		cQuiet.type = TYPE_QUIET;
		cQuiet.distance = 0;
		cQuiet.step = 0;
		cQuiet.duration = (int) ((endTimestamp - startTimestamp) / 60);
		final float userWeight = PreferenceUtil.readFloat(App.i(), C.sp.weight, DEFAULT_WEIGHT);
		final int userAge = PreferenceUtil.readInt(App.i(), C.sp.user_age, DEFAULT_AGE);
		final boolean userMale = PreferenceUtil.readBoolean(App.i(), C.sp.sex, DEFAULT_MALE);
		cQuiet.calorie = calcExerciseCalories(0, userWeight, cQuiet.duration, userAge, userMale, cQuiet.type, 0);
		cQuiet.recordTime = startTimestamp;
		long mTimeInfo = (startTimestamp + (isBeginFrom2000 ? RingBleController.offsetTime : 0)) * 1000;
		cQuiet.recordTimeInfo = sdfRecordTime.format(new Date(mTimeInfo));
		return cQuiet;
	}

	private static Calories replaceInstance(int type, float distance, int duration, float calorie, int stepNumber, int t2000ToCurr,
			DailySummary dailySummary, Calories lastCalories) {
		lastCalories.type = type;
		lastCalories.distance = distance;
		lastCalories.duration = duration;
		lastCalories.calorie = calorie;
		lastCalories.recordTime = t2000ToCurr;
		lastCalories.recordTimeInfo = sdfRecordTime.format(new Date((t2000ToCurr + RingBleController.offsetTime) * 1000));
		lastCalories.step = stepNumber;
		lastCalories.dailySummary = dailySummary;
		lastCalories.update(lastCalories.getId());
		return lastCalories;
	}

	public static Calories mergeInstance(Calories dealObject, Calories lastCalories) {
		lastCalories.distance += dealObject.distance;
		lastCalories.duration += dealObject.duration;
		lastCalories.calorie += dealObject.calorie;
		lastCalories.step += dealObject.step;
		return lastCalories;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public int getType() {
		return type;
	}

	public void setType(int type) {
		this.type = type;
	}

	public float getDistance() {
		return distance;
	}

	public void setDistance(float distance) {
		this.distance = distance;
	}

	public int getDuration() {
		return duration;
	}

	public void setDuration(int duration) {
		this.duration = duration;
	}

	public float getCalorie() {
		return calorie;
	}

	public void setCalorie(float calorie) {
		this.calorie = calorie;
	}

	public DailySummary getDailySummary() {
		return dailySummary;
	}

	public void setDailySummary(DailySummary dailySummary) {
		this.dailySummary = dailySummary;
	}

	public String getRecordTimeInfo() {
		return recordTimeInfo;
	}

	public void setRecordTimeInfo(String recordTimeInfo) {
		this.recordTimeInfo = recordTimeInfo;
	}

	public long getRecordTime() {
		return recordTime;
	}

	public void setRecordTime(long recordTime) {
		this.recordTime = recordTime;
	}

	public int getStep() {
		return step;
	}

	public void setStep(int step) {
		this.step = step;
	}

	/** 获得Calories对应当天0点的时间戳 (秒) */
	public long calcTodayStartTimeStamp() {
		Date current = new Date((recordTime + RingBleController.offsetTime) * 1000);
		String curr = FormatUtil.formatDate(current, FormatUtil.yyyyMMdd);
		return FormatUtil.parseDate(curr, FormatUtil.yyyyMMdd).getTime() / 1000;
	}

	/** 获得Calories当前时间对应的时间戳(秒) */
	public long calcTodayCurrTimeStamp() {
		return recordTime + RingBleController.offsetTime;
	}

}
